package aNN;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;

public class Layer {
	public List<Neuron> Neurons;
	
	public Layer()
	{
		this.Neurons = new ArrayList<Neuron>();
	}
	
	public void Calculate()
	{
		for (int i = 0; i < Neurons.size(); i++)
		{
			Neurons.get(i).Calculate();
		}
	}
	
	public HashMap<Neuron, NeuronOutputPair> TempCalculate(HashMap<Neuron, NeuronOutputPair> prevLayer)
	{
		HashMap<Neuron, NeuronOutputPair> returnVal = new HashMap<Neuron, NeuronOutputPair>();
		for (int i = 0; i < Neurons.size(); i++)
		{
			Neuron neuron = Neurons.get(i);
			returnVal.put(neuron, neuron.TempCalculate(prevLayer));
		}
		return returnVal;
	}
	
	public HashMap<Neuron, RefDouble> BackPropagate(double eta, double dMicron, ErrorCompute errorMethod, HashMap<Weight, RefDouble> dErr_wrt_dw)
	{
//		HashMap<Weight, RefDouble> dErr_wrt_dw = new HashMap<Weight, RefDouble>();
		HashMap<Neuron, RefDouble> dErr_wrt_dy = new HashMap<Neuron, RefDouble>();
		for (int i = 0; i < Neurons.size(); i++)
		{
			Neuron neuron = Neurons.get(i);
			dErr_wrt_dy.put(neuron, new RefDouble(neuron.BackPropagate(errorMethod.GetdErr_wrt_dx(neuron), dErr_wrt_dw)));
		}
//		Iterator<Entry<Weight, RefDouble>> weightIterator = dErr_wrt_dw.entrySet().iterator();
//		while (weightIterator.hasNext())
//		{
//			Entry<Weight, RefDouble> pairs = weightIterator.next();
//			Weight weight = pairs.getKey();
//			RefDouble value = pairs.getValue();
//			weight.setWeight(weight.getWeight() - (eta  /*(weight.getDiagHessian() + dMicron) */ * value.value));
//		}
		return dErr_wrt_dy;
	}
	
	public HashMap<Neuron, RefDouble> SecondOrderBackPropagate(double eta, ErrorCompute errorMethod)
	{
		HashMap<Weight, RefDouble> d2Err_wrt_d2w = new HashMap<Weight, RefDouble>();
		HashMap<Neuron, RefDouble> d2Err_wrt_d2y = new HashMap<Neuron, RefDouble>();
		for (int i = 0; i < Neurons.size(); i++)
		{
			Neuron neuron = Neurons.get(i);
			d2Err_wrt_d2y.put(neuron, new RefDouble(neuron.SecondOrderBackPropagate(errorMethod.Getd2Err_wrt_d2x(neuron), d2Err_wrt_d2w)));
		}
		Iterator<Entry<Weight, RefDouble>> weightIterator = d2Err_wrt_d2w.entrySet().iterator();
		while (weightIterator.hasNext())
		{
			Entry<Weight, RefDouble> pairs = weightIterator.next();
			Weight weight = pairs.getKey();
			RefDouble value = pairs.getValue();
			weight.setDiagHessian(weight.getDiagHessian() + value.value);
		}
		return d2Err_wrt_d2y;
	}
}
